home *** CD-ROM | disk | FTP | other *** search
/ PC Media 7 / PC MEDIA CD07.iso / share / prog / cm / cmbintr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-06  |  10.6 KB  |  414 lines

  1. // CmBinTr.cpp
  2. // -----------------------------------------------------------------
  3. // Compendium - C++ Container Class Library
  4. // Copyright (C) 1992-1994, Glenn M. Poorman, All rights reserved
  5. // -----------------------------------------------------------------
  6. // Binary tree implementation.
  7. // -----------------------------------------------------------------
  8.  
  9. #include <cm/include/cmbintr.h>
  10.  
  11.  
  12. // "CmBinaryTree" is the tree copy constructor.
  13. //
  14. CmBinaryTree::CmBinaryTree(const CmBinaryTree& aTree)
  15. {
  16.   _root = NULL;
  17.   copy   (aTree);
  18.   balance();
  19. }
  20.  
  21.  
  22. // "~CmBinaryTree" is the tree destructor.
  23. //
  24. CmBinaryTree::~CmBinaryTree()
  25. {
  26.   removeAll();
  27. }
  28.  
  29.  
  30. // "=" assignment operator copies the contents of the specified tree
  31. // into this tree.
  32. //
  33. CmBinaryTree& CmBinaryTree::operator=(const CmBinaryTree& aTree)
  34. {
  35.   if (&aTree != this)
  36.   {
  37.     removeAll();
  38.     copy     (aTree);
  39.     balance  ();
  40.   }
  41.   return *this;
  42. }
  43.  
  44.  
  45. // "add" adds the specified object to this tree.
  46. //
  47. Bool CmBinaryTree::add(CmObject* pObj)
  48. {
  49.   if (!pObj) return FALSE;
  50.  
  51.   CmBinaryTreeNode *newnode = new CmBinaryTreeNode(pObj);
  52.   if (!newnode) return FALSE;
  53.  
  54.   if (!_root)                                // Tree is empty.  Add at root.
  55.     _root = newnode;
  56.  
  57.   else                                       // Tree is not empty.
  58.   {
  59.     int               comp   = pObj->compare(_root->_data);
  60.     CmBinaryTreeNode *rover  = (comp < 0) ? _root->_left : _root->_right;
  61.     CmBinaryTreeNode *parent = _root;
  62.  
  63.     while (rover)                            // Search for vacant slot.
  64.     {
  65.       parent = rover;
  66.       comp   = pObj->compare(rover->_data);
  67.       rover  = (comp < 0) ? rover->_left : rover->_right;
  68.     }
  69.  
  70.     if (comp < 0) parent->_left  = newnode;  // Add new node appropriately.
  71.     else          parent->_right = newnode;
  72.   }
  73.   _size++;
  74.   return TRUE;
  75. }
  76.  
  77.  
  78. // "remove" removes the first occurrence of an object that isEqual
  79. // to the specified object from the tree.
  80. //
  81. Bool CmBinaryTree::remove(CmObject* pObj)
  82. {
  83.   if (!_root || !pObj) return FALSE;           // Exit if empty tree.
  84.  
  85.   CmBinaryTreeNode *rover  = _root;            // Init for search.
  86.   CmBinaryTreeNode *parent = NULL;
  87.   Bool              done   = FALSE;
  88.  
  89.   while (rover && !done)                       // Search for object.
  90.   {
  91.     int comp = pObj->compare(rover->_data);
  92.     if (comp != 0)                             // Advance to next node.
  93.     {
  94.       parent = rover;
  95.       rover  = (comp < 0) ? rover->_left : rover->_right;
  96.     }
  97.  
  98.     else                                       // Object was found.
  99.     {
  100.       CmBinaryTreeNode *temp1 = rover;         // Save pointer to object.
  101.  
  102.       if (rover->_right == NULL)
  103.         rover = rover->_left;
  104.  
  105.       else if (rover->_right->_left == NULL)
  106.       {
  107.         rover        = rover->_right;
  108.         rover->_left = temp1->_left;
  109.       }
  110.  
  111.       else
  112.       {
  113.         CmBinaryTreeNode *temp2 = rover->_right;
  114.         while (temp2->_left->_left) temp2 = temp2->_left;
  115.         rover         = temp2->_left;
  116.         temp2->_left  = rover->_right;
  117.         rover->_left  = temp1->_left;
  118.         rover->_right = temp1->_right;
  119.       }
  120.  
  121.       if (!parent)                             // Object to remove is root.
  122.         _root = rover;
  123.  
  124.       else
  125.       {
  126.         comp = temp1->_data->compare(parent->_data);
  127.         if (comp < 0) parent->_left  = rover;
  128.         else          parent->_right = rover;
  129.       }
  130.  
  131.       if (ownsObjects()) delete temp1->_data;  // Delete data if owned.
  132.       delete temp1;                            // Delete node.
  133.       _size--;
  134.       done = TRUE;
  135.     }
  136.   }
  137.   return done;
  138. }
  139.  
  140.  
  141. // "lookup" returns the first occurrence of an object which isEqual
  142. // to the specified object.
  143. //
  144. CmObject* CmBinaryTree::lookup(CmObject *pObj) const
  145. {
  146.   if (!_root || !pObj) return NULL;
  147.  
  148.   CmBinaryTreeNode *rover = _root;
  149.   CmObject         *ret   = NULL;
  150.  
  151.   while (rover && !ret)
  152.   {
  153.     int comp = pObj->compare(rover->_data);
  154.     if (comp == 0) ret    = rover->_data;
  155.     else           rover  = (comp < 0) ? rover->_left : rover->_right;
  156.   }
  157.   return ret;
  158. }
  159.  
  160.  
  161. // "contains" checks to see if an object that isEqual to the specified
  162. // object exists in the tree.
  163. //
  164. Bool CmBinaryTree::contains(CmObject *pObj) const
  165. {
  166.   return (lookup(pObj) == NULL) ? FALSE : TRUE;
  167. }
  168.  
  169.  
  170. // "occurrences" returns the number of objects in the tree
  171. // isEqual to the specified object.
  172. //
  173. unsigned CmBinaryTree::occurrences(CmObject *pObj) const
  174. {
  175.   unsigned             total = 0;
  176.   CmBinaryTreeIterator iterator(*this);
  177.   while (!iterator.done())
  178.     if (pObj->isEqual(iterator.next()))
  179.       total++;
  180.   return total;
  181. }
  182.  
  183.  
  184. // "removeAll" removes all the objects from the tree.
  185. //
  186. void CmBinaryTree::removeAll()
  187. {
  188.   if (_root)
  189.   {
  190.     killNode(_root, ownsObjects());
  191.     if (ownsObjects()) delete _root->_data;
  192.     delete _root;
  193.     _root = NULL;
  194.     _size = 0;
  195.   }
  196. }
  197.  
  198.  
  199. // "balance" balances the current contents of the binary tree.
  200. //
  201. void CmBinaryTree::balance()
  202. {
  203.   CmTQueue<CmBinaryTreeNode*> *que = new CmTQueue<CmBinaryTreeNode*>;
  204.   CmBinaryTreeIterator iterator(*this);
  205.   while (!iterator.done())
  206.   {
  207.     CmBinaryTreeNode *newnode = new CmBinaryTreeNode(iterator.next());
  208.     if (newnode) que->push(newnode);
  209.   }
  210.  
  211.   Bool owns = ownsObjects();
  212.   if (owns) ownsObjects(FALSE);
  213.   removeAll();
  214.   if (owns) ownsObjects(TRUE);
  215.  
  216.   balanceHalf(que, 0, que->size() - 1);
  217.   delete que;
  218. }
  219.  
  220.  
  221. // "newIterator" creates and returns a new tree iterator.
  222. //
  223. CmIterator* CmBinaryTree::newIterator() const
  224. {
  225.   return new CmBinaryTreeIterator(*this);
  226. }
  227.  
  228.  
  229. // "write" writes the tree contents to the specified reserve file.
  230. //
  231. Bool CmBinaryTree::write(CmReserveFile& file) const
  232. {
  233.   return CmContainer::write(file);
  234. }
  235.  
  236.  
  237. // "read" reads objects from the specified reserve file.
  238. //
  239. Bool CmBinaryTree::read(CmReserveFile& file)
  240. {
  241.   Bool success = CmContainer::read(file);
  242.   if (success) balance();
  243.   return success;
  244. }
  245.  
  246.  
  247. // "balanceHalf" is called recursively to balance part of the tree.
  248. //
  249. void CmBinaryTree::balanceHalf(CmTQueue<CmBinaryTreeNode*> *que,
  250.                                int low, int high)
  251. {
  252.   if (low <= high)
  253.   {
  254.     int mid = (low + high) / 2;
  255.     add(((*que)[mid])->_data);
  256.     balanceHalf(que, mid + 1, high);
  257.     balanceHalf(que, low, mid - 1);
  258.   }
  259. }
  260.  
  261.  
  262. // "killNode" is a recursively called static function which takes a
  263. // subtree and destroys the left and right branches.
  264. //
  265. void CmBinaryTree::killNode(CmBinaryTreeNode* subTree, Bool owns)
  266. {
  267.   if (subTree->_left)
  268.   {
  269.     killNode(subTree->_left, owns);
  270.     if (owns) delete subTree->_left->_data;
  271.     delete subTree->_left;
  272.     subTree->_left = NULL;
  273.   }
  274.  
  275.   if (subTree->_right)
  276.   {
  277.     killNode(subTree->_right, owns);
  278.     if (owns) delete subTree->_right->_data;
  279.     delete subTree->_right;
  280.     subTree->_right = NULL;
  281.   }
  282. }
  283.  
  284.  
  285. // "CmBinaryTreeIterator" is the constructor for the tree iterator
  286. // class.
  287. //
  288. CmBinaryTreeIterator::CmBinaryTreeIterator(const CmBinaryTree &Tr)
  289.                                            : _tree(Tr)
  290. {
  291.   _stack = new CmTStack<CmBinaryTreeNode*>;
  292.   _node  = _tree._root;
  293.   if (_node)
  294.   {
  295.     while (_node->_left)
  296.     {
  297.       _stack->push(_node);
  298.       _node = _node->_left;
  299.     }
  300.   }
  301. }
  302.  
  303.  
  304. // "~CmBinaryTreeIterator" is the destructor for the tree iterator
  305. // class.
  306. //
  307. CmBinaryTreeIterator::~CmBinaryTreeIterator()
  308. {
  309.   delete _stack;
  310. }
  311.  
  312.  
  313. // "next" returns a pointer to the object pointed to by the iterator.  The
  314. // iterator is then advanced to the next node in the tree.
  315. //
  316. CmObject* CmBinaryTreeIterator::next()
  317. {
  318.   if (!_node) return NULL;                        // Iteration is over.
  319.  
  320.   CmObject* retValue = _node->_data;              // Save off object pointer.
  321.  
  322.   if (_node->_right)                              // If there is a right
  323.   {                                               // branch, advance to it
  324.     _stack->push(_node);                          // and descend all the way
  325.     _node = _node->_right;                        // down it's left side.
  326.     while (_node->_left)
  327.     {
  328.       _stack->push(_node);
  329.       _node = _node->_left;
  330.     }
  331.   }
  332.  
  333.   else                                            // Otherwise, back up the
  334.   {                                               // tree until we are back
  335.     CmBinaryTreeNode* temp;                       // at the top or until we
  336.     do                                            // are no longer a right
  337.     {                                             // branch.
  338.       temp  = _node;
  339.       if (_stack->size() == 0) _node = NULL;
  340.       else                     _node = _stack->pop();
  341.     } while (_node && _node->_right == temp);
  342.   }
  343.   return retValue;
  344. }
  345.  
  346.  
  347. // "previous" returns a pointer to the current object and decrements
  348. // the iterator.
  349. //
  350. CmObject* CmBinaryTreeIterator::previous()
  351. {
  352.   if (!_node) return NULL;                        // Iteration is over.
  353.  
  354.   CmObject* retValue = _node->_data;              // Save off object pointer.
  355.  
  356.   if (_node->_left)                               // If there is a left
  357.   {                                               // branch, advance to it
  358.     _stack->push(_node);                          // and descend all the way
  359.     _node = _node->_left;                         // down it's right side.
  360.     while (_node->_right)
  361.     {
  362.       _stack->push(_node);
  363.       _node = _node->_right;
  364.     }
  365.   }
  366.  
  367.   else                                            // Otherwise, back up the
  368.   {                                               // tree until we are back
  369.     CmBinaryTreeNode* temp;                       // at the top or until we
  370.     do                                            // are no longer a left
  371.     {                                             // branch.
  372.       temp  = _node;
  373.       if (_stack->size() == 0) _node = NULL;
  374.       else                     _node = _stack->pop();
  375.     } while (_node && _node->_left == temp);
  376.   }
  377.   return retValue;
  378. }
  379.  
  380.  
  381. // "first" moves the iterator to the first object in the tree.
  382. //
  383. void CmBinaryTreeIterator::first()
  384. {
  385.   _stack->removeAll();
  386.   _node = _tree._root;
  387.   if (_node)
  388.   {
  389.     while (_node->_left)
  390.     {
  391.       _stack->push(_node);
  392.       _node = _node->_left;
  393.     }
  394.   }
  395. }
  396.  
  397.  
  398. // "last" moves the iterator to the right most tree node thus
  399. // pointing to the last object in the tree.
  400. //
  401. void CmBinaryTreeIterator::last()
  402. {
  403.   _stack->removeAll();
  404.   _node = _tree._root;
  405.   if (_node)
  406.   {
  407.     while (_node->_right)
  408.     {
  409.       _stack->push(_node);
  410.       _node = _node->_right;
  411.     }
  412.   }
  413. }
  414.